package com.alit.ibot.robot.wechat.controller;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xml.sax.SAXException;

import com.alit.ibot.robot.projectvariable.PVU;
import com.alit.ibot.robot.wechat.data.LastMessage;
import com.alit.ibot.robot.wechat.data.WechatMessageType;
import com.alit.ibot.robot.wechat.service.RobotWechatService;
import com.alit.ibot.robot.wechat.util.DOMXMLUtil;
import com.alit.ibot.robot.wechat.util.WechatCryptUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * @author litong
 * @date 2019年5月30日_下午10:56:48
 * @version 1.0
 * @desc
 */
@RestController
@RequestMapping("wechat")
@Slf4j
public class WechatController {
  @Autowired
  private RobotWechatService robotWechatService;

  public Map<String, LastMessage> lastMessage = new ConcurrentHashMap<>();

  @RequestMapping
  public void index(HttpServletRequest request, HttpServletResponse response) {
    // 进行验证
    String echostr = request.getParameter("echostr");
    PrintWriter out = null;
    if (echostr != null) {
      try {
        out = response.getWriter();
      } catch (IOException e) {
        e.printStackTrace();
      }
      out.print(echostr);
      log.info("验证通过");
      return;
    }
    // 获取请求体中的参数值 start
    String postContent = null;
    InputStream inputStream = null;
    try {
      inputStream = request.getInputStream();// 获取HttpServeltRequest中请求数据
      postContent = IOUtils.toString(inputStream, "UTF-8");// 将InputStream转换为String
    } catch (IOException e1) {
      e1.printStackTrace();
    }
    // 获取请求体中的参数值 end
    if (StringUtils.isEmpty(postContent)) {
      response.setContentType("text/html;charset=UTF-8");
      try {
        out = response.getWriter();
      } catch (IOException e) {
        e.printStackTrace();
      }
      out.println("没有发送任何数据");
      return;
    }

    String timestamp = request.getParameter("timestamp");
    String nonce = request.getParameter("nonce");
    String msgSignature = request.getParameter("msg_signature");

    Map<String, String> requestMap = null;
    try {
      requestMap = this.getWechatFromXML(postContent, msgSignature, timestamp, nonce);// 解密微信消息
    } catch (ParserConfigurationException e) {
      e.printStackTrace();
    } catch (SAXException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }

    if (isSameMessage(requestMap)) {
      // 如果和上次接收到的消息相同,则不进行处理,因为已经收到该消息,没有必要再次处理
      return;
    }

    String toXML = robotWechatService.getToWechatXML(requestMap); // 获取发送到微信平台xml内容
    if (PVU.isDev()) {
      // log.info("加密前消息:" + toXML);
    }

    String result = this.getToWechatCryptXML(toXML, timestamp, nonce); // 对消息加密
    if (PVU.isDev()) {
      // log.info("加密后消息:" + toXML);
    }

    response.setContentType("text/xml;charset=UTF-8");// 设置返回头部
    try {
      out = response.getWriter();
    } catch (IOException e) {
      e.printStackTrace();
    }
    out.println(result); // 返回消息
    // System.out.println(result);
  }

  private boolean isSameMessage(Map<String, String> requestMap) {
    String fromUserName = requestMap.get("FromUserName");
    String msgType = requestMap.get("MsgType");
    boolean retval = false;
    String md5Hex = null;
    long currentTimeMillis = System.currentTimeMillis();
    if (msgType.equals(WechatMessageType.text)) {
      String content = requestMap.get("Content");
      md5Hex = DigestUtils.md5Hex(content); // md5加密
      LastMessage lastTime = lastMessage.get(fromUserName);
      if (lastTime == null) {
        lastMessage.put(fromUserName, new LastMessage(md5Hex, currentTimeMillis)); // 更新数据
        return false; // 放行
      }
      if (currentTimeMillis - lastTime.getMillis() > 10000) {
        lastMessage.put(fromUserName, new LastMessage(md5Hex, currentTimeMillis)); // 更新数据
        // 10秒之前发送的,放行
        return false;
      }

      if (md5Hex.equals(lastTime.getMd5Hex())) {
        // 可以获取到用户消息,在10s之内接收到,且内容还相同
        lastMessage.put(fromUserName, new LastMessage(md5Hex, currentTimeMillis)); // 更新数据
        return true; // 放行
      }
    }
    return retval;
  }

  /**
   * 解密微信消息 并转为Map
   */
  private Map<String, String> getWechatFromXML(String postContent, String msgSignature, String timestamp, String nonce)
      throws Exception {
    String fromXML = WechatCryptUtil.getFromXML(postContent, msgSignature, timestamp, nonce); // 获取明文xml字符串
    Map<String, String> fromXMLMap = DOMXMLUtil.parseXmlToMap(fromXML); // 将xml字符转为map
    return fromXMLMap;
  }

  /**
   * 若接受的密文消息,则对消息进行加密 若接受的是明文消息,则不对消息进行加密
   * 
   * @param toXML
   * @return
   */
  private String getToWechatCryptXML(String toXML, String timestamp, String nonce) {
    String retval = null;
    if (WechatCryptUtil.isCrypt) { // 密文消息,加密
      String cryptXML = WechatCryptUtil.getToXML(toXML, timestamp, nonce);
      retval = cryptXML;
    } else { // 明文消息,不加密
      retval = toXML;
    }
    return retval;
  }
}
